package com.logansoft.servicehomework.controller;

import com.alibaba.fastjson.JSON;
import com.logansoft.servicehomework.entity.CommonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchPhraseQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author liqiye
 * @description 测试es客户端
 * @date 2021/7/15
 */

@RestController
@Api(tags = "测试es客户端")
public class TestESController {

    @Autowired
    private RestHighLevelClient restHighLevelClient;  // 这里名字必须要对上

    private String index_name = "test_index";

    // 创建索引
    @PostMapping("/createIndex")
    @ApiOperation(value = "创建索引", notes="")
    public CommonResult createIndex() throws IOException {
        // 创建索引请求，里面指定 _index 注意不能用大写字母
        CreateIndexRequest request = new CreateIndexRequest(index_name);
        // 客户端执行请求，请求后获取相应
        CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
        return new CommonResult(200, "创建es索引成功",response);
    }

    // 判断索引是否存在
    @GetMapping("/existIndex")
    public CommonResult existIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest(index_name);
        boolean exists = restHighLevelClient.indices().exists(request,RequestOptions.DEFAULT);
        return new CommonResult(200, "索引<" + index_name + ">是否存在：" + exists);
    }

    // 判断索引是否存在，删除索引
    @PostMapping("/deleteIndex")
    public CommonResult deleteIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest(index_name);
        boolean exists = restHighLevelClient.indices().exists(request,RequestOptions.DEFAULT);
        if(exists){
            DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index_name);
            AcknowledgedResponse response = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
            return new CommonResult(200, "删除es索引成功",response);
        }
        return new CommonResult(200, "索引<" + index_name + ">不存在：");
    }



    // 给索引添加文档
    @PostMapping("/addDocument")
    public CommonResult addDocument() throws IOException {
        HashMap<String, String> map = new HashMap<>();
        map.put("id", "1");
        map.put("name", "李启业");
        map.put("age", "25");
        // 创建一个索引请求对象
        IndexRequest request = new IndexRequest(index_name);
        request.id("1");
        request.timeout("1s");  // 这次请求的超时时间
        // 对象数据
        request.source(JSON.toJSONString(map), XContentType.JSON);
        // 客户端发送请求
        IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        return new CommonResult(200, "给索引<" + index_name + ">创建一条文档成功", response);
    }

    // 判断文档是否存在
    @GetMapping("/existDocument")
    public CommonResult existDocument() throws IOException {
        GetRequest request = new GetRequest(index_name, "1");
        // 不获取返回的 _source 的上下文
        request.fetchSourceContext(new FetchSourceContext(false));
        // 排序字段
        request.storedFields("_none_");
        boolean exists = restHighLevelClient.exists(request, RequestOptions.DEFAULT);
        return new CommonResult(200, "索引<" + index_name + ">的id为1的文档是否存在：" + exists);
    }

    // 获取文档的信息
    @GetMapping("/getDocument")
    public CommonResult getDocument() throws IOException {
        GetRequest request = new GetRequest(index_name, "1");
        GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        HashMap map = JSON.parseObject(response.getSourceAsString(), HashMap.class);
        System.out.println(map);
        return new CommonResult(200, "索引<" + index_name + ">的id为1的文档信息查询成功" , response);
    }

    // 更新文档的信息
    @PostMapping("/updateDocument")
    public CommonResult updateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest(index_name, "1");
        request.timeout("1s");
        HashMap<String, String> map = new HashMap<>();
        map.put("age", "26");
        request.doc(JSON.toJSONString(map), XContentType.JSON);
        UpdateResponse response = restHighLevelClient.update(request, RequestOptions.DEFAULT);
        return new CommonResult(200, "索引<" + index_name + ">的id为1的文档修改成功", response);
    }

    // 删除文档
    @PostMapping("/deleteDocument")
    public CommonResult deleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest(index_name, "1");
        request.timeout("1s");
        DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        return new CommonResult(200, "索引<" + index_name + ">的id为1的文档删除成功", response);
    }

    // 批量导入文档（将数据库中初始化的大量数据先导进去）
    // @PostMapping("/bulkAddDocument")
    // public CommonResult bulkAddDocument() throws IOException {
    //     BulkRequest request = new BulkRequest();
    //     request.timeout("5s");
    //     ArrayList<Payment> list = new ArrayList<>();
    //     list.add(new Payment(1, "这是李启业的一段文档！！"));
    //     list.add(new Payment(2, "这是小李子的一段文档！！"));
    //     list.add(new Payment(3, "这是张三的一段文档！！"));
    //     list.add(new Payment(4, "这是李四的一段文档！！"));
    //     // 批量处理
    //     for (int i = 0; i< list.size(); i++){
    //         // 这里批量 新增、修改、删除 都可以，用对应的处理类就可以了
    //         request.add(
    //                 new IndexRequest(index_name)
    //                         .id(i + 1 + "")  // 这里可以不指定id，然后自动生成
    //                         .source(JSON.toJSONString(list.get(i)), XContentType.JSON)
    //         );
    //     }
    //     BulkResponse response = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
    //     return new CommonResult(200, "批量处理，是否失败(false代表成功)：" + response.hasFailures(), response);
    // }

    // 查询
    @GetMapping("/search")
    public CommonResult search() throws IOException {
        SearchRequest request = new SearchRequest(index_name);

        // 构建搜素条件
        SearchSourceBuilder builder = new SearchSourceBuilder();

        // 查询条件 用 QueryBuilders 工具来实现 ，match开头的是模糊、term开头的是精确
        // MatchAllQueryBuilder query = QueryBuilders.matchAllQuery();  // 全部查询，这种不指定关键词查询的，高亮是不会生效的
        // TermQueryBuilder query = QueryBuilders.termQuery("id", "1");  // 精确匹配
        // MatchQueryBuilder query = QueryBuilders.matchQuery("serial", "李启业");  // 分词模糊匹配（就是按照分词法则，分开的词能模糊匹配的都查出来，必须分页，因为他会将词拆分成每个字的）
        MatchPhraseQueryBuilder query = QueryBuilders.matchPhraseQuery("name", "李启业");  // 整个词语的 模糊匹配
        builder.query(query);

        // 指定查询出来的字段
        String[] includeSource = {"name","id"};
        String[] excludeSource = {};  // 其实这个为空，也就是只查出includeSource包含的字段
        builder.fetchSource(includeSource, excludeSource);

        // 分页，不写或者不指定参数，有默认值，就是查出满足的全部
        builder.from();
        builder.size();

        // 排序字段
        // builder.sort("id", SortOrder.ASC);

        // 设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name");
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        highlightBuilder.requireFieldMatch(false);  // 多个高亮显示
        builder.highlighter(highlightBuilder);

        // 查询的超时时间
        builder.timeout(new TimeValue(5, TimeUnit.SECONDS));


        request.source(builder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        System.out.println(JSON.toJSONString(response.getHits()));
        for (SearchHit documentFields : response.getHits().getHits()){
            HashMap map = JSON.parseObject(documentFields.getSourceAsString(), HashMap.class);

            // 将高亮的属性替换掉原字段
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HighlightField serial = highlightFields.get("name");
            if(serial != null){
                map.put("name", serial.fragments()[0] + "");
                // Text[] fragments = serial.fragments();
                // String s_serial = "";
                // for (Text text : fragments){
                //     s_serial += text;
                // }
                // payment.setSerial(s_serial);
            }

            System.out.println(map);
        }

        return new CommonResult(200, "查询成功", response);
    }


}
